package util;

import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

public class FreemarkerUtils {
  /** 私有构造方法，避免通过new操作符生成对象 */
  private FreemarkerUtils() {}

  /** 默认的编码格式 */
  private static final String Encode = "UTF-8";

  /** 缓存级配置项（作用于无模板文件情况下使用freemarker） */
  private static Configuration _cacheConfig =
      new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);

  /** 文件级配置项（作用于有模板文件情况下使用freemarker） */
  private static Configuration _fileConfig =
      new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);

  /** 缓存级配置项实际的模板加载器 */
  private static StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
  //
  static {
    System.out.println("初次加载FreemarkerUtils时进行初始化...");
    //    Set the preferred charset template files are stored in.
    _cacheConfig.setDefaultEncoding(Encode);
    _fileConfig.setDefaultEncoding(Encode);
    //    TemplateExceptionHandler.DEBUG_HANDLER useful when you developing non-HTML templates.
    //    TemplateExceptionHandler.HTML_DEBUG_HANDLER useful when you developing HTML templates.
    //    TemplateExceptionHandler.	IGNORE_HANDLER that simply skips the failing instructions,
    // letting the template continue executing.
    //    TemplateExceptionHandler.RETHROW_HANDLER that simply re-throws the exception; this should
    // be used in most production systems.
    _cacheConfig.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
    _fileConfig.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
    // Don't log exceptions inside FreeMarker that it will thrown at you anyway
    _cacheConfig.setLogTemplateExceptions(false);
    _fileConfig.setLogTemplateExceptions(false);
    // Wrap unchecked exceptions thrown during template processing into TemplateException-s.
    _cacheConfig.setWrapUncheckedExceptions(true);
    _fileConfig.setWrapUncheckedExceptions(true);

    _fileConfig.setClassForTemplateLoading(FreemarkerUtils.class, "/");
    _cacheConfig.setTemplateLoader(stringTemplateLoader);
  }

  /**
   * 是否存在模板文件
   *
   * @param templateFilePath 模板路径
   * @return 存在结果
   * @throws IOException IO异常
   */
  public static boolean isExistTemplateFile(String templateFilePath) throws IOException {
    Template template = _fileConfig.getTemplate(templateFilePath);
    return template != null;
  }

  /**
   * 是否存在指定名称的缓存模板
   *
   * @param cacheName 特定缓存的名称
   * @return 存在结果
   * @throws IOException IO异常
   */
  public static boolean isExistTemplateCache(String cacheName) throws IOException {
    Template template = (Template) stringTemplateLoader.findTemplateSource(cacheName);
    return template != null;
  }

  public static void putTemplateCache(String cachePrefix, String templateContent)
      throws IOException {
    if (!isExistTemplateCache(cachePrefix + templateContent.hashCode())) {
      stringTemplateLoader.putTemplate(cachePrefix + templateContent.hashCode(), templateContent);
    }
  }

  public static String parseTemplateFile(String templateFilePath, Map<String, Object> root)
      throws IOException, TemplateException {
    if (isExistTemplateFile(templateFilePath)) {
      Template template = _fileConfig.getTemplate(templateFilePath);
      StringWriter out = new StringWriter();
      template.process(root, out);
      return out.toString();
    }
    return null;
  }

  public static String parseTemplateCache(
      String cachePrefix, String templateContent, Map<String, Object> root)
      throws IOException, TemplateException {
    if (!isExistTemplateCache(cachePrefix + templateContent.hashCode())) {
      putTemplateCache(cachePrefix, templateContent);
    }
    Template template = _cacheConfig.getTemplate(cachePrefix + templateContent.hashCode());
    StringWriter out = new StringWriter();
    template.process(root, out);
    return out.toString();
  }

}
